//Copyright 2010 Balazs Keri, Imre Keri
//
//This file is part of FireworksCreator.
//
//FireworksCreator is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//FireworksCreator is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with FireworksCreator.  If not, see <http://www.gnu.org/licenses/>.
//
#include <global.h>
#include <QtDebug>
#include <common/restoreerror.h>
#include "document.h"
#include "primitive.h"
//
Primitive::Primitive(unsigned int p_type)
:
   state(incomplete),type(p_type)
{
}
Primitive::~Primitive()
{
}
void Primitive::prepare_base(const Document *p_doc)
{
   Q_ASSERT(state==incomplete);
   state=before_first;
}
UiError Primitive::exec(Document *p_doc)
{
   Q_ASSERT(state==before_first||state==before||state==after);
   /* to be able to resume interrupted PrimitiveGroups because of errors */
   if(state==after)
   {
      qDebug()<<"Primitive: exec() called in after state";
      return UiError();
   }
   UiError ret;
   p_doc->emit_pre_primitive(*this);
   if(!(ret=exec_impl(p_doc)).success())
   {
      p_doc->emit_fail_primitive(*this);
      return ret;
   }
   state=after;
   p_doc->emit_post_primitive(*this);
   return UiError();
}
UiError Primitive::undo(Document *p_doc)
{
   Q_ASSERT(state==after||state==before);
   if(state==before)
   {
      qDebug()<<"Primitive: undo() called in before state";
      return UiError();
   }
   UiError ret;
   p_doc->emit_pre_primitive(*this);
   if(!(ret=undo_impl(p_doc)).success())
   {
      p_doc->emit_fail_primitive(*this);
      return ret;
   }
   state=before;
   p_doc->emit_post_primitive(*this);
   return UiError();
}
Primitive::State Primitive::get_state() const
{
   return state;
}
void Primitive::store_data(QDataStream &p_stream) const
{
   p_stream<<type;
   store_data_impl(p_stream);
   p_stream<<int(state);
}
void Primitive::restore_data(RestoreStream &p_stream)
{
   restore_data_impl(p_stream);
   int s;p_stream>>s;
   switch(s)
   {
   case incomplete:
      state=incomplete;
      break;
   case before_first:
      state=before_first;
      break;
   case before:
      state=before;
      break;
   case after:
      state=after;
      break;
   default:
      throw RestoreError(qApp->translate("Primitive","bad state value while reading Primitive"));
   }
}
void Primitive::store_data_impl(QDataStream &p_stream) const
{
}
void Primitive::restore_data_impl(RestoreStream &p_stream)
{
}
class PrimitiveCreatorStore
{
public:
   static PrimitiveCreatorStore &get();
   void add_creator_function(unsigned int p_type,Primitive::CreatorFunction p_f);
   Primitive::CreatorFunction get_creator_function(unsigned int p_type) const;
private:
   static PrimitiveCreatorStore *instance;
   QHash<unsigned int,Primitive::CreatorFunction> map;
};
PrimitiveCreatorStore *PrimitiveCreatorStore::instance=0;
PrimitiveCreatorStore &PrimitiveCreatorStore::get()
{
   if(!instance)
      instance=new PrimitiveCreatorStore;
   return *instance;
}
void PrimitiveCreatorStore::add_creator_function(unsigned int p_type,Primitive::CreatorFunction p_f)
{
   Q_ASSERT(!map.contains(p_type));
   map[p_type]=p_f;
}
Primitive::CreatorFunction PrimitiveCreatorStore::get_creator_function(unsigned int p_type) const
{
   QHash<unsigned int,Primitive::CreatorFunction>::const_iterator const i=map.find(p_type);
   if(i==map.end())
      return 0;
   return i.value();
}
Primitive *Primitive::create(RestoreStream &p_stream)
{
   unsigned int type;p_stream>>type;
   CreatorFunction cr=PrimitiveCreatorStore::get().get_creator_function(type);
   if(!cr)
      throw RestoreError(qApp->translate("Primitive","unknown Primitive type"));
   return (*cr)(type, p_stream);
}
void Primitive::install_creator_function(unsigned int p_type,CreatorFunction p_f)
{
   PrimitiveCreatorStore::get().add_creator_function(p_type,p_f);
}
//
PrimitiveDelegate::PrimitiveDelegate(unsigned int p_type)
:
   type(p_type)
{
}
PrimitiveDelegate::~PrimitiveDelegate()
{
}
void PrimitiveDelegate::store_data(QDataStream &p_stream) const
{
   p_stream<<type;
   store_data_impl(p_stream);
}
void PrimitiveDelegate::restore_data(RestoreStream &p_stream) 
{
   restore_data_impl(p_stream);
}
void PrimitiveDelegate::store_data_impl(QDataStream &p_stream) const
{
}
void PrimitiveDelegate::restore_data_impl(RestoreStream &p_stream)
{
}
class PrimitiveDelegateCreatorStore
{
public:
   static PrimitiveDelegateCreatorStore &get();
   void add_creator_function(unsigned int p_type,PrimitiveDelegate::CreatorFunction p_f);
   PrimitiveDelegate::CreatorFunction get_creator_function(unsigned int type) const;
private:
   static PrimitiveDelegateCreatorStore *instance;
   QHash<unsigned int,PrimitiveDelegate::CreatorFunction> map;
};
PrimitiveDelegateCreatorStore *PrimitiveDelegateCreatorStore::instance=0;
PrimitiveDelegateCreatorStore &PrimitiveDelegateCreatorStore::get()
{
   if(!instance)
      instance=new PrimitiveDelegateCreatorStore;
   return *instance;
}
void PrimitiveDelegateCreatorStore::add_creator_function(unsigned int p_type,PrimitiveDelegate::CreatorFunction p_f)
{
   Q_ASSERT(!map.contains(p_type));
   map[p_type]=p_f;
}
PrimitiveDelegate::CreatorFunction PrimitiveDelegateCreatorStore::get_creator_function(unsigned int p_type) const
{
   QHash<unsigned int,PrimitiveDelegate::CreatorFunction>::const_iterator const i=map.find(p_type);
   if(i==map.end())
      return 0;
   return i.value();
}
PrimitiveDelegate *PrimitiveDelegate::create(RestoreStream &p_stream)
{
   unsigned int type;p_stream>>type;
   CreatorFunction cr=PrimitiveDelegateCreatorStore::get().get_creator_function(type);
   if(!cr)
      throw RestoreError(qApp->translate("Primitive","unknown Primitive type"));
   return (*cr)(type,p_stream);
}
void PrimitiveDelegate::install_creator_function(unsigned int p_type,CreatorFunction p_f)
{
   PrimitiveDelegateCreatorStore::get().add_creator_function(p_type,p_f);
}
